package com.ilxqx.framework.system.service.impl;

import com.ilxqx.framework.security.po.SimpleUserInfo;
import com.ilxqx.framework.security.util.AuthUtils;
import com.ilxqx.framework.system.constant.TableFieldConstants;
import com.ilxqx.framework.system.repository.FrameworkRepository;
import com.ilxqx.framework.system.service.CrudService;
import com.ilxqx.framework.system.util.EntityCheckingUtils;
import com.ilxqx.framework.system.util.ReflectionUtils;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.Assert;

import javax.transaction.Transactional;
import java.util.List;
import java.util.Optional;

/**
 * 增删改查Service实现类
 * @author venus
 */
public abstract class AbstractCrudServiceImpl<T, ID> implements CrudService<T, ID> {

    /**
     * Jpa仓库实现注入
     */
    private FrameworkRepository<T, ID> repository;

    public AbstractCrudServiceImpl(FrameworkRepository<T, ID> repository) {
        this.repository = repository;
    }

    /**
     * 根据ID获取记录
     *
     * @param id 记录ID
     * @return 实体对象
     */
    @Override
    public Optional<T> get(ID id) {
        Assert.notNull(id, "需要查找记录的主键不能为空");
        return this.repository.findById(id);
    }

    /**
     * 根据ID判断记录是否存在
     *
     * @param id 记录ID
     * @return bool
     */
    @Override
    public boolean exists(ID id) {
        Assert.notNull(id, "需要判断是否存在的记录的主键不能为空");
        return this.repository.existsById(id);
    }

    /**
     * 获取所有记录
     *
     * @return 实体对象List
     */
    @Override
    public List<T> getList() {
        return this.repository.findAll();
    }

    /**
     * 根据多个ID获取多条记录
     *
     * @param idList 记录ID集合
     * @return 记录List
     */
    @Override
    public List<T> getList(Iterable<ID> idList) {
        Assert.notNull(idList, "根据ID集合查找记录的集合不能为空");
        return this.repository.findAllById(idList);
    }

    /**
     * 根据排序获取所有记录
     *
     * @param sort 排序对象
     * @return 实体对象List
     */
    @Override
    public List<T> getList(Sort sort) {
        return this.repository.findAll(sort);
    }

    /**
     * 根据操作用户ID获取所有相关记录
     *
     * @param operationUserId 操作用户ID
     * @return 实体对象List
     */
    @Override
    public List<T> getList(ID operationUserId) {
        Assert.notNull(operationUserId, "操作用户的ID不能为空");
        return repository.findAll((Specification<T>) (root, query, criteriaBuilder) ->
                criteriaBuilder.and(criteriaBuilder.equal(root.get(TableFieldConstants.OPERATION_USER_ID_FIELD_NAME), operationUserId)));
    }

    /**
     * 根据操作用户ID和排序对象获取所有相关记录
     *
     * @param sort            排序对象
     * @param operationUserId 操作用户ID
     * @return 实体对象List
     */
    @Override
    public List<T> getList(Sort sort, ID operationUserId) {
        Assert.notNull(operationUserId, "操作用户的ID不能为空");
        return repository.findAll((Specification<T>) (root, query, criteriaBuilder) ->
                criteriaBuilder.and(criteriaBuilder.equal(root.get(TableFieldConstants.OPERATION_USER_ID_FIELD_NAME), operationUserId)), sort);
    }

    /**
     * 获取表中记录总数
     *
     * @return 记录数
     */
    @Override
    public long count() {
        return this.repository.count();
    }

    /**
     * 添加记录
     *
     * @param entity 实体对象
     * @return 添加后的实体对象
     */
    @Override
    @Transactional(rollbackOn = Exception.class)
    public T add(T entity) {
        Assert.notNull(entity, "需要添加的实体对象不能为空");
        EntityCheckingUtils.checkPrimaryKeyIsNull(entity);
        // 更新操作用户信息
        SimpleUserInfo simpleUserInfo = AuthUtils.getLoggedUserSimpleInfo();
        ReflectionUtils.setEntityOperationUserSimpleInfo(entity, simpleUserInfo);
        return this.repository.save(entity);
    }

    /**
     * 添加多条记录
     *
     * @param entities 实体对象集合
     * @return 添加后的实体对象集合
     */
    @Override
    @Transactional(rollbackOn = Exception.class)
    public Iterable<T> addAll(Iterable<T> entities) {
        Assert.notNull(entities, "需要添加的实体迭代对象不能为空");
        EntityCheckingUtils.checkAnyEntityPrimaryKeyIsNull(entities);
        // 更新操作用户信息
        SimpleUserInfo simpleUserInfo = AuthUtils.getLoggedUserSimpleInfo();
        entities.forEach(entity -> ReflectionUtils.setEntityOperationUserSimpleInfo(entity, simpleUserInfo));
        return this.repository.saveAll(entities);
    }

    /**
     * 更新记录
     *
     * @param entity 实体对象
     * @return 更新后的实体对象
     */
    @Override
    @Transactional(rollbackOn = Exception.class)
    public T modify(T entity) {
        Assert.notNull(entity, "需要更新的实体对象不能为空");
        EntityCheckingUtils.checkPrimaryKeyNotNull(entity);
        return this.repository.save(entity);
    }

    /**
     * 更新多条记录
     *
     * @param entities 实体对象集合
     * @return 更新后的实体对象集合
     */
    @Override
    @Transactional(rollbackOn = Exception.class)
    public Iterable<T> modifyAll(Iterable<T> entities) {
        Assert.notNull(entities, "需要更新的实体迭代对象不能为空");
        EntityCheckingUtils.checkAnyEntityPrimaryKeyNotNull(entities);
        return this.repository.saveAll(entities);
    }

    /**
     * 根据记录ID删除记录
     *
     * @param id 记录ID
     */
    @Override
    @Transactional(rollbackOn = Exception.class)
    public void deleteById(ID id) {
        Assert.notNull(id, "需要删除的记录主键不能为空");
        this.repository.deleteById(id);
    }

    /**
     * 根据实体对象删除记录
     *
     * @param entity 实体对象
     */
    @Override
    @Transactional(rollbackOn = Exception.class)
    public void delete(T entity) {
        Assert.notNull(entity, "需要删除记录的实体对象不能为空");
        EntityCheckingUtils.checkPrimaryKeyNotNull(entity);
        this.repository.delete(entity);
    }

    /**
     * 删除所有指定实体对象的记录
     *
     * @param entities 实体对象集合
     */
    @Override
    @Transactional(rollbackOn = Exception.class)
    public void deleteAll(Iterable<T> entities) {
        Assert.notNull(entities, "需要删除的实体迭代对象不能为空");
        EntityCheckingUtils.checkAnyEntityPrimaryKeyNotNull(entities);
        this.repository.deleteAll(entities);
    }

}
